﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MiniJavaScanner
{
    public enum TokenType : sbyte
    {
        EOF = - 127,
        ERROR = -1,        
        ID = 0,
        INTEGER,
        SEMICOLON, DOT, COMMA,
        ASSIGMENT,
        LEFT_PAREN, RIGHT_PAREN,
        LEFT_BRACE, RIGHT_BRACE,
        LEFT_BRACKET, RIGHT_BRACKET,
        PLUS, MINUS, MULTIPLICATION, DIVISION,
        
        NOT, AND, OR, LT, GT,

        TRUE, FALSE,
        IF, ELSE,
        WHILE,
        CLASS,
        PUBLIC,
        STATIC, MAIN,
        EXTENDS,
        THIS,
        NEW,
        RETURN,

        COMMENT,

        TYPE_DECL,   // INT BOOLEAN VOID STRING INT_ARR STRING_ARR

        AND_BITWISE, OR_BITWISE
    }

    class Token
    {
        public TokenType Type { get; set; }
        public string Attribute { get; set; }

        public Token(TokenType type, string value  = "")
        {
            this.Type = type;
            this.Attribute = value;              
        }

        override public string ToString()
        {
            string optPart = (this.Attribute.Length == 0) ? "" : ", \"" + this.Attribute + "\"";
            return "<" + this.Type + optPart + ">";
        }

        override public int GetHashCode()
        {
            return this.Type.GetHashCode() + this.Attribute.GetHashCode();
        }

        override public bool Equals(object obj)
        {
            Token otherToken = (Token)obj;
            if (otherToken == null)
            {
                return base.Equals(obj);
            }

            return (this.Type == otherToken.Type)
                    && (this.Attribute.CompareTo(otherToken.Attribute) == 0);
        }
    }

    static class KeywordTokenCreator
    {
        private static Dictionary<string, TokenType> keywords = new Dictionary<string, TokenType>() 
        {
                {"this", TokenType.THIS},
                {"new", TokenType.NEW},
                {"return", TokenType.RETURN},
                {"static", TokenType.STATIC},                
                {"main", TokenType.MAIN},
                {"class", TokenType.CLASS},
                {"public", TokenType.PUBLIC},
                {"if", TokenType.IF},
                {"else", TokenType.ELSE},
                {"while", TokenType.WHILE},
                {"extends", TokenType.EXTENDS},

                {"void", TokenType.TYPE_DECL},
                {"int", TokenType.TYPE_DECL},
                {"boolean", TokenType.TYPE_DECL},
                {"String", TokenType.TYPE_DECL},

                {"true", TokenType.TRUE},
                {"false", TokenType.FALSE}
        };

        public static Token CreateByString(string strKeyword)
        {
            TokenType type = keywords.ContainsKey(strKeyword) ? keywords[strKeyword]
                                                              : TokenType.ID;
            return new Token(type, strKeyword);
        }
    }
}
